package com.mushuilingfeng.ddd.user.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.jwt.JWT;
import com.mushuilingfeng.ddd.user.domain.base.BusinessException;
import com.mushuilingfeng.ddd.user.domain.base.Ii8nCode;
import com.mushuilingfeng.ddd.user.domain.user.entity.User;
import com.mushuilingfeng.ddd.user.infrastructure.cache.ICacheClient;
import com.mushuilingfeng.ddd.user.service.ITokenService;
import com.mushuilingfeng.ddd.user.vo.LoginToken;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;

/**
 * @author 沐水淋风
 * @date 2024/9/30
 */
@Service
public class TokenServiceImpl implements ITokenService {
    private final ICacheClient cacheClient;
    @Value("${jwt.secret}")
    private String jwtSecret;
    @Value("${jwt.expireTime}")
    private Long expireTime;
    
    public TokenServiceImpl(ICacheClient cacheClient) {
        this.cacheClient = cacheClient;
    }
    
    private LoginToken createToken(User user, String clientId, String refreshToken) {
        JWT jwt = JWT.create();
        jwt.setKey(jwtSecret.getBytes(StandardCharsets.UTF_8));
        jwt.setPayload("user", user);
        LoginToken.LoginTokenBuilder builder = LoginToken.builder()//
                .token(jwt.sign())//
                .expireTime(System.currentTimeMillis() + expireTime);
        if (null != refreshToken) {
            builder.refreshToken(refreshToken);
        } else {
            builder.refreshToken(MD5.create().digestHex16(clientId + user.getId() + "" + System.currentTimeMillis()));
        }
        return builder.build();
    }
    
    private void putCache(LoginToken loginToken, User user) {
        cacheClient.set(loginToken.getToken(), user, loginToken.getExpireTime());
        cacheClient.set(loginToken.getToken() + "#refresh", loginToken, loginToken.getExpireTime());
        cacheClient.set(loginToken.getRefreshToken(), loginToken.getToken(), loginToken.getExpireTime());
        cacheClient.set(user.getId() + "#token", loginToken.getToken(), loginToken.getExpireTime());
    }
    
    private void deleteCache(LoginToken loginToken) {
        cacheClient.delete(loginToken.getToken());
        cacheClient.delete(loginToken.getToken() + "#refresh");
        cacheClient.delete(loginToken.getRefreshToken());
    }
    
    @Override
    public LoginToken authenticate(User user, String clientId) {
        LoginToken loginToken = createToken(user, clientId, null);
        putCache(loginToken, user);
        return loginToken;
    }
    
    
    @Override
    public User getUserByToken(String token) {
        return cacheClient.get(token);
    }
    
    @Override
    public LoginToken reNewToken(String refreshToken) {
        String oldToken = cacheClient.get(refreshToken);
        if (null == oldToken) {
            throw new BusinessException(Ii8nCode.PARAM_INVALID);
        }
        User user = cacheClient.get(oldToken);
        if (null == user) {
            throw new BusinessException(Ii8nCode.PARAM_INVALID);
        }
        LoginToken loginToken = createToken(user, null, refreshToken);
        putCache(loginToken, user);
        return loginToken;
    }
    
    @Override
    public void deleteToken(String token) {
        LoginToken loginToken = cacheClient.get(token + "#refresh");
        if (null == loginToken) {
            return;
        }
        deleteCache(loginToken);
    }
    
    @Override
    public void invalidateUserToken(Long userId) {
        String token = cacheClient.get(userId + "#token");
        if (StrUtil.isBlankIfStr(token)) {
            return;
        }
        deleteToken(token);
    }
    
}
